package org.kernely.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.shiro.SecurityUtils;
import org.kernely.security.dao.UserDetailsDAO;
import org.kernely.security.persistence.User;
import org.kernely.security.persistence.UserDetails;
import org.kernely.ui.admin.KernelyAdminPresenter;
import org.kernely.ui.admin.KernelyAdminView;
import org.kernely.ui.home.KernelyHomePresenter;
import org.kernely.ui.home.KernelyHomeView;
import org.kernely.ui.mvp.IKernelyPresenter;
import org.kernely.ui.mvp.IKernelyView;
import org.kernely.ui.mvp.KernelyBundleMenu;
import org.kernely.ui.mvp.KernelyEvent;
import org.kernely.ui.mvp.KernelyEventReceiver;
import org.kernely.ui.mvp.KernelyPresenter;
import org.kernely.ui.mvp.KernelyViewPresenterManager;
import org.kernely.ui.profile.KernelyProfileEvent;
import org.kernely.ui.profile.KernelyProfilePresenter;
import org.kernely.ui.profile.KernelyProfileView;
import org.kernely.ui.services.KernelyUIBundle;
import org.kernely.ui.settings.KernelySettingsPresenter;
import org.kernely.ui.settings.KernelySettingsView;

import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.Layout;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;

public class MainApplicationPresenter extends KernelyPresenter<MainApplicationView> implements KernelyEventReceiver{

	/**
	 * The Serial Version ID
	 */
	private static final long serialVersionUID = 72541857764606790L;

	private IKernelyPresenter actualPresenter;
	private Map<String, KernelyViewPresenterManager> applicationViewPresenter = new HashMap<String, KernelyViewPresenterManager>();

	/**
	 * MainApplicationPresenter's contructor
	 */
	public MainApplicationPresenter(){
		// We create the presenters and insert it into the list.
		KernelyViewPresenterManager homeAssociation = new KernelyViewPresenterManager();
		KernelyViewPresenterManager profileAssociation = new KernelyViewPresenterManager();
		KernelyViewPresenterManager adminAssociation = new KernelyViewPresenterManager();
		KernelyViewPresenterManager settingsAssociation = new KernelyViewPresenterManager();
		
		homeAssociation.put(KernelyHomeView.class, KernelyHomePresenter.class);
		profileAssociation.put(KernelyProfileView.class, KernelyProfilePresenter.class);
		adminAssociation.put(KernelyAdminView.class, KernelyAdminPresenter.class);
		settingsAssociation.put(KernelySettingsView.class, KernelySettingsPresenter.class);
		// Adding the static pages HOME, PROFILE and ADMIN
		applicationViewPresenter.put("HOME_PAGE", homeAssociation);
		applicationViewPresenter.put("PROFILE_PAGE", profileAssociation);
		applicationViewPresenter.put("ADMIN_PAGE", adminAssociation);
		applicationViewPresenter.put("SETTINGS_PAGE", settingsAssociation);
	}

	/**
	 * This method logout the user. He is automatically redirected to the KernelyLoginView (see the code in MainApplication).
	 */
	final private void logout(){
		SecurityUtils.getSubject().logout();
	}

	/**
	 * @see org.kernely.core.service.IKernelyPresenter#bind()
	 */
	@Override
	public final void bind() {

		//Initialize the Home button in the menu bar
		MenuBar.Command goToHome = new MenuBar.Command() {
			private static final long serialVersionUID = 11604150612L;
			public void menuSelected(MenuItem selectedItem) {
				showView("HOME_PAGE", KernelyHomeView.class);
			}
		};
		this.view.getHomeMenu().addItem("Home", goToHome);

		//Initialize the Applications menu in the menu bar
		this.view.setApplications(this.view.getApplicationsMenu().addItem("Applications", null));
		initializeApplicationsMenu();

		//Initialize the Logout button in the menu bar
		MenuBar.Command logout = new MenuBar.Command(){
			/**
			 * the Serial Version ID
			 */
			private static final long serialVersionUID = -6084826317075580609L;

			public void menuSelected(MenuItem selectedItem) {
				logout();
			}
		};
		this.view.getLogoutMenu().addItem("Logout", logout);

		//Initialize the user's menu
		User u = MainApplication.getSecurityService().getCurrentUser();
		UserDetailsDAO uddao = UserDetailsDAO.getInstance();
		UserDetails ud = uddao.getUserDetails(u);
		String currentUser = ud.getFirstname() + " " + ud.getName();

		this.view.setChangeProfileItem(this.view.getProfileMenu().addItem(currentUser, null));
		MenuBar.Command profile = new MenuBar.Command(){
			/**
			 * The Serial Version ID
			 */
			private static final long serialVersionUID = -8743922539554977153L;

			public void menuSelected(MenuItem selectedItem) {
				showView("PROFILE_PAGE", KernelyProfileView.class);
			}
		};
		MenuItem profileItem = this.view.getUserMenuItem().addItem("Profile", profile);
		profileItem.setIcon(new ThemeResource("img/user_basic.png"));

		MenuBar.Command settings = new MenuBar.Command(){
			/**
			 * The Serial Version ID
			 */
			private static final long serialVersionUID = -1261011451098015153L;

			public void menuSelected(MenuItem selectedItem) {
				showView("SETTINGS_PAGE", KernelySettingsView.class);
			}
		};
		MenuItem settingsItem = this.view.getUserMenuItem().addItem("Settings", settings);
		settingsItem.setIcon(new ThemeResource("img/settings.png"));

		MainApplication.getEventBus().addListener(this);

		// The default view is HOME PAGE
		showView("HOME_PAGE", KernelyHomeView.class);
	}

	/**
	 * This method initialize the applications menu, where bundles menu are displayed and where there is the Administration menu.
	 */
	final private void initializeApplicationsMenu(){
		MenuItem menuitem;
		this.view.getApplications().removeChildren();
		// Create a list of all KernelyBundle deployed
		ArrayList<KernelyUIBundle> bundlesList = new ArrayList<KernelyUIBundle>(MainApplication.getKernelyUIBundleService().getUIBundles());
		for (KernelyUIBundle bundle : bundlesList){
			final KernelyUIBundle b = bundle;
			// Create an sub item for each view provided by the bundle
			KernelyBundleMenu bundlemenu = bundle.getMenu();
			// If the bundle provides a menu
			if(bundlemenu != null){
				// add an item for each bundle into applications menu
				menuitem = this.view.getApplications().addItem(bundle.getName(),null);
				// Set the menu icon of the bundle
				menuitem.setIcon(bundle.getMenuIcon());
				Set<Entry<String, Class<? extends IKernelyView>>> entryset = bundlemenu.entrySet();
				for(Entry<String, Class<? extends IKernelyView>> entry : entryset){
					final Entry<String, Class<? extends IKernelyView>> e = entry;
					// Create a command associated to the menuitem, if the user has the role to see it					
					//The user can see the menu only if everybody can see it or if he has the correct role.
					Set<String> rolesSet = bundlemenu.getRoles(e.getValue());
					if (rolesSet == null || MainApplication.getSecurityService().currentUserHasOneOf(rolesSet)){
					MenuBar.Command mc = new MenuBar.Command() {
						/**
						 * The Serial Version ID
						 */
						private static final long serialVersionUID = 4222305156649103383L;

						public void menuSelected(MenuItem selectedItem) {
							showView(b.getName(), e.getValue());
						}
					};
					menuitem.addItem(e.getKey(), mc);
					}
				}
				// If the bundle has no sub-menu accessible to the user, we remove it
				if (menuitem.getSize() <= 0){
					this.view.getApplications().removeChild(menuitem);
				}
				applicationViewPresenter.put(bundle.getName(), bundle.getViewPresenter());
			}
		}

		// Only administrators can view the administration panel
		if(MainApplication.getSecurityService().currentUserHasOneOf("Administrator")){
			// The menu item to go to the administration panel.
			MenuBar.Command mc = new MenuBar.Command() {
				/**
				 * The Serial Version ID
				 */
				private static final long serialVersionUID = 1156131681L;
	
				public void menuSelected(MenuItem selectedItem) {
					showView("ADMIN_PAGE", KernelyAdminView.class);
				}
			};
			MenuItem item = this.view.getApplications().addItem("Administration",mc);
			item.setIcon(new ThemeResource("img/admin16.png"));
		}
	}

	/**
	 * This method display a KernelyView into the center panel.
	 * @param bundleName The name of the bundle which contains the view
	 * @param viewClass The class to show (must extends IKernelyView).
	 */
	public final void showView(String bundleName, Class<? extends IKernelyView> viewClass){
		try {
			// Retrieve the presenter
			IKernelyPresenter presenter = ((KernelyViewPresenterManager) applicationViewPresenter.get(bundleName)).getPresenterInstance(viewClass);
			// Retrieve the view
			IKernelyView view = viewClass.newInstance();
			// Associate the view to the presenter
			presenter.setView(view);

			if (actualPresenter != null){
				actualPresenter.unset();				
			}
			actualPresenter = presenter;

			if(this.view.getCenterLayout() != null){
				this.view.removeComponent(this.view.getCenterLayout());
			}
			this.view.setCenterLayout((Layout)presenter.getView());
			this.view.addComponent((Layout)presenter.getView());
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @see org.kernely.core.service.KernelyEventReceiver#handleViewEvent(KernelyEvent)
	 */
	@Override
	public final void handleKernelyEvent(KernelyEvent event) {
		if (event instanceof KernelyProfileEvent){
			// Update name in the menu bar
			//Initialize the user's menu
			User u = MainApplication.getSecurityService().getCurrentUser();
			UserDetailsDAO uddao = new UserDetailsDAO();
			UserDetails ud = uddao.getUserDetails(u);
			String currentUser = ud.getFirstname() + " " + ud.getName();
			this.view.getUserMenuItem().setText(currentUser);
		}
		if(event instanceof KernelyUIBundleDetectionEvent){
			initializeApplicationsMenu();
		}
	}
}
